<?php
defined('IN_MY_PHP') || die(0);
/**
 * 实现单例模式，为便于使用，实现数组访问接口
 *
 * @author netmou <leiyanfo@sina.com>
 */

class Master implements ArrayAccess
{
	private static $single = null;
	private $instanceContainer = array();
	private $classContainer = array();
	
	private function __construct($classes = null, $init = false)
	{
		$this->loadClass($classes, $init);
	}
	
	public static function singleton($classes = null, $init = false)
	{
		if (!isset(self::$single)) {
			self::$single = new self($classes, $init);
		} else {
			self::$single->loadClass($classes, $init);
		}

		return self::$single;
	}
	public function loadClass($classes, $init = true, $path = LIB_PATH)
	{
		if($classes != null){
			if (!is_array($classes)) {
				$classes = array($classes);
			}
			foreach ($classes as $key => $class) {
				if (!in_array($class, $this->classContainer)) {
					$fileName = $class.'.class.php';
					$this->contain($fileName, $path);
					$this->classContainer[] = $class;
				}
				$key = is_numeric($key)? $class : $key;
				if ($init && !isset($this->instanceContainer[$key])) {
					try { // 可能抛出异常的类 eg.PDOMySQLDriver
						$this->instanceContainer[$key] = new $class();
					} catch (Exception $e) {
						trigger_error($e->getMessage(), E_USER_ERROR);
					}
				}
			}
		}
	}
	
	/**
	 * 安全导入文件内容
	 * @param  [type] $file       文件名
	 * @param  [type] $path       路径
	 * @param  array  $importVars 导入变量
	 * @return [type]            返回引入内容
	 */
	public function contain($file, $path = null, $importVars = array())
	{
		$file = preg_replace('/[\\\\\\/]/', DS, $file);
		if ($path != null) {
			$file = rtrim(preg_replace('/[\\\\\\/]/', DS, $path), DS) . DS . $file;
		}

		if (file_exists($file) && is_readable($file)) {
			//禁止访问不在网站根目录下的内容
			if (stripos(realpath($file), PROJECT_PATH) !== 0) {
				trigger_error("file:'{$file}' access denied.", E_USER_ERROR);
			}
			// 导入对引入文件可见的变量
			extract($importVars);

			return include $file; // the method must be include
		}
		trigger_error("file:'{$file}' is not found.", E_USER_ERROR);
	}

	/**
	 * 检测一下是否是本地请求（即，开发环境）
	 * @return boolean 是本地请求返回true
	 */
	public function isLocalRequest()
	{
		static $is_local = null;
		if($is_local === null){
			$is_local = false;
			$addrInfo = array($_SERVER['HTTP_CLIENT_IP'], $_SERVER['HTTP_X_FORWARDED_FOR'], $_SERVER['REMOTE_ADDR']);
			foreach($addrInfo as $addr){
				if(preg_match('/(^127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$)|(^::1$)/', $addr)){
					$is_local = true;
				}
			}
		}

		return $is_local;
	}

	/**
	 * @override 对象数组化set方式
	 */
	public function offsetSet($offset, $value)
	{
		if (!is_scalar($offset) || $offset === '') {
			trigger_error("Offset:'{$offset}' must be a valid label", E_USER_ERROR);
		} else {
			$this->instanceContainer[$offset] = $value;
		}
	}
	
	/**
	 * @override 对象数组化是exists方式
	 */
	public function offsetExists($offset)
	{
		return isset($this->instanceContainer[$offset]);
	}

	/**
	 * @override 对象数组化unset方式
	 */
	public function offsetUnset($offset)
	{
		unset($this->instanceContainer[$offset]);
	}

	/**
	 * @override 对象数组化get方式
	 */
	public function offsetGet($offset)
	{
		$this->loadClass($offset);

		return $this->instanceContainer[$offset];
	}
}